import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import * as dayjs from 'dayjs';

/**
 * 日期转换拦截器
 * 用于自动转换响应中的日期格式
 */
@Injectable()
export class TransformDateInterceptor implements NestInterceptor {
  // 用于缓存已格式化的日期，避免重复计算
  private dateCache = new Map<string, string>();
  
  /**
   * 拦截器入口方法
   * @param context 执行上下文
   * @param next 调用处理器
   */
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(
      map(data => {
        try {
          return this.formatDates(data);
        } catch (error) {
          console.error('Date transformation error:', error);
          // 转换失败时返回原始数据
          return data;
        }
      })
    );
  }

  /**
   * 递归格式化对象中的所有日期
   * @param data 需要处理的数据
   */
  private formatDates(data: any): any {
    if (!data) return data;

    // 对于原始类型直接返回
    if (typeof data !== 'object') return data;

    // 处理数组类型
    if (Array.isArray(data)) {
      return data.map(item => this.formatDates(item));
    }

    // 处理对象类型
    const formatted = Object.create(null); // 创建一个没有原型链的纯对象
    
    for (const [key, value] of Object.entries(data)) {
      formatted[key] = this.transformValue(value);
    }

    return formatted;
  }

  /**
   * 转换单个值
   * @param value 需要转换的值
   */
  private transformValue(value: any): any {
    // 处理 Date 对象
    if (value instanceof Date) {
      return this.getCachedDateString(value);
    }

    // 处理 ISO 格式的日期字符串
    if (this.isISODateString(value)) {
      return this.getCachedDateString(new Date(value));
    }

    // 递归处理嵌套对象
    if (typeof value === 'object' && value !== null) {
      return this.formatDates(value);
    }

    return value;
  }

  /**
   * 获取缓存的日期字符串，如果缓存中没有则格式化并缓存
   * @param date Date 对象
   */
  private getCachedDateString(date: Date): string {
    const timestamp = date.getTime().toString();
    if (!this.dateCache.has(timestamp)) {
      this.dateCache.set(
        timestamp,
        dayjs(date).format('YYYY-MM-DD HH:mm:ss')
      );
    }
    return this.dateCache.get(timestamp)!;
  }

  /**
   * 判断一个值是否为 ISO 格式的日期字符串
   * @param value 需要判断的值
   */
  private isISODateString(value: any): boolean {
    if (typeof value !== 'string') return false;
    
    // ISO 日期字符串的正则表达式匹配
    const isoDatePattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d*)?(?:Z|[-+]\d{2}:?\d{2})?$/;
    if (!isoDatePattern.test(value)) return false;
    
    // 额外验证是否为有效日期
    return !isNaN(Date.parse(value));
  }
}
